import json
from django.shortcuts import render,HttpResponse,redirect
from django.http import JsonResponse
from django_redis import get_redis_connection
from web import models
from utils.encrypt import uid
import datetime

def price_show(request):
    price_list = models.PricePolicy.objects.exclude(price=0)
    
    context = {
        'price_list': price_list
    }
    
    return render(request, 'web/price_show.html', context)


def policy_payment(request, policy_id):
    """ 支付页面"""
    # 1. 价格策略（套餐）policy_id
    policy_object = models.PricePolicy.objects.filter(id=policy_id, category=2).first()
    if not policy_object:
        return redirect('/web/price')

    # 2. 要购买的数量
    number = request.GET.get('number', '')
    if not number or not number.isdecimal():
        return redirect('/web/price')
    number = int(number)
    if number < 1:
        return redirect('/web/price')

    # 3. 计算原价
    origin_price = number * policy_object.price

    # 4.之前购买过套餐(之前掏钱买过）
    balance = 0
    _object = None
    if request.tracer.price_policy.category == 2:
        # 找到之前订单：总支付费用 、 开始~结束时间、剩余天数 = 抵扣的钱
        # 之前的实际支付价格
        _object = models.Transaction.objects.filter(user=request.tracer.user, status=2).order_by('-id').first()
        total_timedelta = _object.end_datetime - _object.start_datetime
        balance_timedelta = _object.end_datetime - datetime.datetime.now()
        if total_timedelta.days == balance_timedelta.days:
            # 按照价值进行计算抵扣金额
            balance = _object.price_policy.price * _object.count / total_timedelta.days * (balance_timedelta.days - 1)
        else:
            balance = _object.price_policy.price * _object.count / total_timedelta.days * balance_timedelta.days

    if balance >= origin_price:
        return redirect('/web/price')

    order_id = uid(request.tracer.user.mobile_phone)
    context = {
        'policy_id': policy_object.id,
        'number': number,
        'origin_price': origin_price,
        'balance': round(balance, 2),
        'total_price': round(origin_price-balance, 2),
        'order_id':order_id
    }
    key_value = json.dumps(context)
    context['policy_object'] = policy_object
    context['transaction'] = _object

    conn = get_redis_connection("default")
    conn.set('payment_{}'.format(request.tracer.user.mobile_phone), 
             key_value, 
             ex=60*30)


    return render(request, 'web/payment.html', context)

def pay_old(request):

    conn = get_redis_connection()
    key = 'payment_{}'.format(request.tracer.user.mobile_phone)
    context_string = conn.get(key)
    if not context_string:
        return redirect('price')
    context = json.loads(context_string.decode('utf-8'))

    # 1. 数据库中生成交易记录（待支付）
    #     等支付成功之后，我们需要把订单的状态更新为已支付、开始&结束时间
    order_id = uid(request.tracer.user.mobile_phone)
    total_price = context['total_price']
    models.Transaction.objects.create(
        status=1,
        order=order_id,
        user=request.tracer.user,
        price_policy_id=context['policy_id'],
        count=context['number'],
        price=total_price
    )

    # 2. 跳转到支付去支付
    #    - 根据申请的支付的信息 + 支付宝的文档 => 跳转链接
    #    - 生成一个支付的链接
    #    - 跳转到这个链接
    # 构造字典
    params = {
        'app_id': "2021000118647540",
        'method': 'alipay.trade.page.pay',
        'format': 'JSON',
        'return_url': "http://127.0.0.1:8000/web/pay/notify/",
        'notify_url': "http://127.0.0.1:8000/web/pay/notify/",
        'charset': 'utf-8',
        'sign_type': 'RSA2',
        'timestamp': datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
        'version': '1.0',
        'biz_content': json.dumps({
            'out_trade_no': order_id,
            'product_code': 'FAST_INSTANT_TRADE_PAY',
            'total_amount': total_price,
            'subject': "tracer payment"
        }, separators=(',', ':'))
    }

    # 获取待签名的字符串
    unsigned_string = "&".join(["{0}={1}".format(k, params[k]) for k in sorted(params)])

    # 签名 SHA256WithRSA(对应sign_type为RSA2)
    from Crypto.PublicKey import RSA
    from Crypto.Signature import PKCS1_v1_5
    from Crypto.Hash import SHA256
    from base64 import decodebytes, encodebytes

    # SHA256WithRSA + 应用私钥 对待签名的字符串 进行签名
    private_key = RSA.importKey(open("files/app_private_key.txt").read())
    signer = PKCS1_v1_5.new(private_key)
    signature = signer.sign(SHA256.new(unsigned_string.encode('utf-8')))

    # 对签名之后的执行进行base64 编码，转换为字符串
    sign_string = encodebytes(signature).decode("utf-8").replace('\n', '')

    # 把生成的签名赋值给sign参数，拼接到请求参数中。

    from urllib.parse import quote_plus
    result = "&".join(["{0}={1}".format(k, quote_plus(params[k])) for k in sorted(params)])
    result = result + "&sign=" + quote_plus(sign_string)

    gateway = "https://openapi.alipaydev.com/gateway.do"
    ali_pay_url = "{}?{}".format(gateway, result)

    return redirect(ali_pay_url)


from django.conf import settings
from utils.alipay import AliPay
def pay(request):
    conn = get_redis_connection()
    key = 'payment_{}'.format(request.tracer.user.mobile_phone)
    context_string = conn.get(key)
    if not context_string:
        return redirect('price')
    context = json.loads(context_string.decode('utf-8'))

    # 1. 数据库中生成交易记录（待支付）
    #     等支付成功之后，我们需要把订单的状态更新为已支付、开始&结束时间
    # order_id = uid(request.tracer.user.mobile_phone)
    order_id = context['order_id']
    total_price = context['total_price']
    # models.Transaction.objects.create(
    models.Transaction.objects.update_or_create(
        status=1,
        order=order_id,
        user=request.tracer.user,
        price_policy_id=context['policy_id'],
        count=context['number'],
        price=total_price
    )
    # 生成支付链接
    from django.urls import reverse
    tracer_return_url = "{scheme}://{host}{path}".format(
                    scheme=request.scheme,
                    host=request.get_host(),
                    path=reverse('web:pay_notify'))
    tracer_notify_url = "{scheme}://{host}{path}".format(
                    scheme=request.scheme,
                    host=request.get_host(),
                    path=reverse('web:pay_notify'))
    ali_pay = AliPay(
        appid=settings.ALI_APPID,
        app_notify_url=tracer_notify_url,
        return_url= tracer_return_url,
        app_private_key_path=settings.ALI_PRI_KEY_PATH,
        alipay_public_key_path=settings.ALI_PUB_KEY_PATH
    )
    query_params = ali_pay.direct_pay(
        subject="tracer payment",  # 商品简单描述
        out_trade_no=order_id,  # 商户订单号
        total_amount=total_price
    )
    pay_url = "{}?{}".format(settings.ALI_GATEWAY, query_params)
    return redirect(pay_url)


def pay_notify(request):
    """ 支付成功之后触发的URL """
    from django.urls import reverse
    tracer_return_url = "{scheme}://{host}{path}".format(
                    scheme=request.scheme,
                    host=request.get_host(),
                    path=reverse('web:pay_notify'))
    tracer_notify_url = "{scheme}://{host}{path}".format(
                    scheme=request.scheme,
                    host=request.get_host(),
                    path=reverse('web:pay_notify'))
    ali_pay = AliPay(
        appid=settings.ALI_APPID,
        app_notify_url= tracer_notify_url,
        return_url= tracer_return_url,
        app_private_key_path=settings.ALI_PRI_KEY_PATH,
        alipay_public_key_path=settings.ALI_PUB_KEY_PATH
    )

    if request.method == 'GET':
        # 只做跳转，判断是否支付成功了，不做订单的状态更新。
        # 支付吧会讲订单号返回：获取订单ID，然后根据订单ID做状态更新 + 认证。
        # 支付宝公钥对支付给我返回的数据request.GET 进行检查，通过则表示这是支付宝返还的接口。
        params = request.GET.dict()
        sign = params.pop('sign', None)
        status = ali_pay.verify(params, sign)
        if status:
            current_datetime = datetime.datetime.now()
            out_trade_no = params['out_trade_no']
            _object = models.Transaction.objects.filter(order=out_trade_no).first()
            if _object:
                _object.status = 2
                _object.start_datetime = current_datetime
                _object.end_datetime = current_datetime + datetime.timedelta(days=365 * _object.count)
                _object.save()
                # 删除对应redis键值        
                conn = get_redis_connection('default')
                key = 'payment_{}'.format(request.tracer.user.mobile_phone)
                conn.delete(key)
                return render(request,'web/pay_success.html') 
                return HttpResponse('支付完成')

        return HttpResponse('支付失败')
    else:
        from urllib.parse import parse_qs
        body_str = request.body.decode('utf-8')
        post_data = parse_qs(body_str)
        post_dict = {}
        for k, v in post_data.items():
            post_dict[k] = v[0]

        sign = post_dict.pop('sign', None)
        status = ali_pay.verify(post_dict, sign)
        if status:
            current_datetime = datetime.datetime.now()
            out_trade_no = post_dict['out_trade_no']
            _object = models.Transaction.objects.filter(order=out_trade_no,user=request.tracer.user).first()

            _object.status = 2
            _object.start_datetime = current_datetime
            from dateutil.relativedelta import relativedelta
            # _object.end_datetime = current_datetime + datetime.timedelta(days=365 * _object.count)
            _object.end_datetime = current_datetime + relativedelta(years=_object.count)
            _object.save()
            
            # 删除对应redis键值        
            conn = get_redis_connection('default')
            key = 'payment_{}'.format(request.tracer.user.mobile_phone)
            conn.delete(key)
            return HttpResponse('success')

        return HttpResponse('error')

def pay_success(request):
    return render(request,'web/pay_success.html') 

def pay_cart(request):
    order_objs = models.Transaction.objects.filter(user=request.tracer.user,status=1).\
        exclude(price_policy_id=1).values('status','order','count','price_policy__title','price_policy__price','price','create_datetime')
    
    history_order_objs = models.Transaction.objects.filter(user=request.tracer.user,status=2).\
        exclude(price_policy_id=1).values('status','order','count','price_policy__title','price_policy__price','price','start_datetime','end_datetime')
    conn = get_redis_connection('default')
    key = 'payment_{}'.format(request.tracer.user.mobile_phone)
    context_string = conn.get(key)
    unpaid_order=None
    unpaid_order_objs=None
    if context_string:
        context_pay = json.loads(context_string.decode('utf-8'))
        unpaid_order = context_pay['order_id']
        unpaid_order_objs = models.Transaction.objects.filter(user=request.tracer.user,status=1,order=unpaid_order).\
        exclude(price_policy_id=1).values('status','order','count','price_policy__title','price_policy__price','price','create_datetime')
        order_objs = models.Transaction.objects.filter(user=request.tracer.user,status=1).\
        exclude(price_policy_id=1).exclude(order=unpaid_order).values('status','order','count','price_policy__title','price_policy__price','price','create_datetime')
    context = {
        'unpaid_order_objs':unpaid_order_objs,
        'order_objs':order_objs,
        'history_order_objs':history_order_objs
    }
    return render(request,'web/pay_cart.html',context)

def pay_order_delete(request):
    ret = {'status':True, 'msg':''}
    if request.method == "GET":
        order_no = request.GET.get('orderNo','')
        if order_no:
            order_obj = models.Transaction.objects.filter(user=request.tracer.user, status=1,order=order_no).first()
            if order_obj:
                order_obj.delete()
                return JsonResponse(ret)
    return redirect('/web/pay/cart') 